package com.xbongbong.saas.analytical.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.AttrLenthConstant;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.domain.entity.FormConfigEntity;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.InstockErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.OutstockErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SettleAccountErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.fund.enums.ModelTypeEnum;
import com.xbongbong.saas.analytical.SaasValidateAnalyticalService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.domain.entity.SettleAccountsEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.InventoryEntityExt;
import com.xbongbong.saas.domain.entity.ext.OutstockEntityExt;
import com.xbongbong.saas.enums.FormConfigEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.ContractOutstockEnum;
import com.xbongbong.saas.enums.business.InventoryEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.ReturnedPurchaseOutstockEnum;
import com.xbongbong.saas.enums.business.WorkOrderOutstockEnum;
import com.xbongbong.saas.help.AnalyticalHelp;
import com.xbongbong.saas.help.SaasOutstockHelp;
import com.xbongbong.saas.help.SaasProductHelp;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.FormConfigModel;
import com.xbongbong.saas.model.FundSetModel;
import com.xbongbong.saas.model.InventoryModel;
import com.xbongbong.saas.model.OutstockModel;
import com.xbongbong.saas.model.SettleAccountsModel;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.util.OutstockUtil;
import com.xbongbong.util.ProductUtil;
import com.xbongbong.util.ValidateUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 吴峰
 * @date 2021/07/15 16:28
 */
@Service("outstockAnalyticalServiceImpl")
public class OutstockValidateAnalyticalServiceImpl implements SaasValidateAnalyticalService {

    @Resource
    private OutstockModel outstockModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private ContractModel contractModel;
    @Resource
    private FormConfigModel formConfigModel;
    @Resource
    private SaasProductHelp saasProductHelp;
    @Resource
    private InventoryModel inventoryModel;
    @Resource
    private SaasOutstockHelp saasOutstockHelp;
    @Resource
    private FundSetModel fundSetModel;
    @Resource
    private SettleAccountsModel settleAccountsModel;
    @Resource
    private AnalyticalHelp analyticalHelp;

    @Override
    public List<Integer> type() {
        return Arrays.asList(XbbRefTypeEnum.OUTSTOCK.getCode(), XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode(), XbbRefTypeEnum.OTHER_OUTSTOCK.getCode(),
                XbbRefTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode(), XbbRefTypeEnum.WORK_ORDER_OUTSTOCK.getCode(), XbbRefTypeEnum.PRODUCTION_MATERIEL_OUTSTOCK.getCode());
    }

    @Override
    public void analyticalData(ValidateDataDTO validateDataDTO) throws XbbException {
        beforeSave(validateDataDTO);
        //没有负责团队的 单负责人
        userTeamHelp.checkPermissionOptionTeam(validateDataDTO);
    }

    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        JSONObject data = validateDataDTO.getData();
        Long dataId = validateDataDTO.getDataId();
        Long taskId = validateDataDTO.getTaskId();
        String corpid = validateDataDTO.getCorpid();
        OutstockEntityExt outstockEntityExt = null;
        Long date = data.getLong(OutstockEnum.TIME.getAttr());
        if (Objects.isNull(date)) {
            throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212041);
        }
        //结账中校验
        String redisHelperValue = paasRedisHelper.getValue(RedisPrefixConstant.SETTLE_ACCOUNTS, corpid);
        if (StringUtil.isNotEmpty(redisHelperValue)) {
            if (date <= DateTimeUtil.getTodayEndInt(Long.valueOf(redisHelperValue))) {
                throw new XbbException(SettleAccountErrorCodeEnum.API_ERROR_254007);
            }
        }
        //获取最近一次结账日期
        SettleAccountsEntity accountsEntity = settleAccountsModel.getLastSettleAccounts(corpid);
        if (dataId != null && !Objects.equals(dataId, 0L)) {
            outstockEntityExt = outstockModel.getByKey(dataId, corpid);
            //校验日期是否受结账限制
            //判断是否是审批编辑
            if (Objects.isNull(taskId)) {
                if (Objects.nonNull(accountsEntity) && Objects.nonNull(accountsEntity.getCheckOutTime())) {
                    if (date <= DateTimeUtil.getTodayEndInt(accountsEntity.getCheckOutTime())) {
                        throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212051);
                    }
                }
            }
        } else {
            String value = paasRedisHelper.getValue(RedisPrefixConstant.PRODUCE_STOCK_FLOW, corpid);
            if (StringUtil.isNotEmpty(value)) {
                throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212038);
            }
            //校验日期是否受结账限制
            if (Objects.nonNull(accountsEntity) && Objects.nonNull(accountsEntity.getCheckOutTime())) {
                if (date <= DateTimeUtil.getTodayEndInt(accountsEntity.getCheckOutTime())) {
                    throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212031);
                }
            }
        }
        Integer businessType = validateDataDTO.getBusinessType();
        OutstockTypeEnum outstockTypeEnum;
        Integer type = data.getInteger(OutstockEnum.TYPE.getAttr());
        if (Objects.isNull(type)) {
            outstockTypeEnum = OutstockTypeEnum.getByStockBusinessType(businessType);
            data.put(OutstockEnum.TYPE.getAttr(), String.valueOf(outstockTypeEnum.getCode()));
        } else {
            outstockTypeEnum = OutstockTypeEnum.getByCode(type);
        }
        setRefType(data,validateDataDTO.getBusinessType());
        Map<String, FieldAttrEntity> explainMap = validateDataDTO.getExplainMap();
        // ==============数据格式校验===================
        // 校验编号长度不超过100且编号存在
        FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
        FieldAttrEntity sheetNo = explainMap.getOrDefault(OutstockEnum.SHEET_NO.getAttr(), fieldAttrEntity);
        if (Objects.nonNull(sheetNo) && Objects.equals(sheetNo.getStrictController(), BasicConstant.ZERO)) {
            ValidateUtil.checkSerialNumber(validateDataDTO.getSerialNo(), Objects.toString(sheetNo.getAttrName(), ""));
        }

        //批次号保存前必填校验
        SaveFormatHelp.batchSaveRequiredCheck(validateDataDTO);

        FieldAttrEntity memoField = explainMap.getOrDefault(OutstockEnum.MEMO.getAttr(), fieldAttrEntity);
        // 校验备注长度
        ValidateUtil.checkFieldEntityLength(data, OutstockEnum.MEMO.getAttr(), Objects.toString(memoField.getAttrName(), ""), AttrLenthConstant.MEMO_MAX_LENGTH);

        SaveFormatHelp.formatLinkBusiness4Save(data, OutstockEnum.WAREHOUSE_ID.getAttr(), OutstockEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr(), OutstockEnum.WAREHOUSE_ID.getFieldType());
        if (data.getJSONArray(OutstockEnum.REF_ID.getAttr()) == null || data.getJSONArray(OutstockEnum.REF_ID.getAttr()).size() == 0) {
            data.remove(OutstockEnum.REF_ID.getAttr());
        }
        SaveFormatHelp.formatLinkBusiness4Save(data, OutstockEnum.REF_ID.getAttr(), OutstockEnum.REF_ID_LINKED_TEXT.getAttr(), OutstockEnum.REF_ID.getFieldType());
        switch (outstockTypeEnum){
            case CONTRACT_OUTSTOCK:
                SaveFormatHelp.formatLinkBusiness4Save(data, ContractOutstockEnum.LINK_CUSTOMER.getAttr(), ContractOutstockEnum.LINK_CUSTOMER_HIDE.getAttr(), ContractOutstockEnum.LINK_CUSTOMER.getFieldType());
                // 如果前端没传根据默认公式计算一下
                if (Objects.isNull(data.getDouble(ContractOutstockEnum.PRODUCT_TOTAL.getAttr()))) {
                    JSONArray productArr = data.getJSONArray(ContractOutstockEnum.PRODUCT.getAttr());
                    if (CollectionsUtil.isNotEmpty(productArr)) {
                        Double productTotal = 0D;
                        for (Object product : productArr) {
                            JSONObject productObj = (JSONObject) product;
                            if (Objects.nonNull(productObj.getDouble(SelectProductEnum.SUBTOTAL.getAttr()))) {
                                productTotal += productObj.getDouble(SelectProductEnum.SUBTOTAL.getAttr());
                            }
                        }
                        data.put(ContractOutstockEnum.PRODUCT_TOTAL.getAttr(), productTotal);
                    } else {
                        data.put(ContractOutstockEnum.PRODUCT_TOTAL.getAttr(), 0);
                    }
                }
                if (Objects.isNull(data.getDouble(ContractOutstockEnum.OTHER_EXPENSE.getAttr()))) {
                    data.put(ContractOutstockEnum.OTHER_EXPENSE.getAttr(), 0);
                }
                if (Objects.isNull(data.getDouble(ContractOutstockEnum.TOTAL_MONEY.getAttr()))) {
                    data.put(ContractOutstockEnum.TOTAL_MONEY.getAttr(), Arith.add(data.getDouble(ContractOutstockEnum.PRODUCT_TOTAL.getAttr()), data.getDouble(ContractOutstockEnum.OTHER_EXPENSE.getAttr())));
                }
                if (Objects.isNull(data.getDouble(ContractOutstockEnum.DISCOUNT_AMOUNT.getAttr()))) {
                    data.put(ContractOutstockEnum.DISCOUNT_AMOUNT.getAttr(), 0);
                }
                // 校验出库金额
                if (Arith.compare(data.getDouble(ContractOutstockEnum.TOTAL_MONEY.getAttr()), 0) < 0) {
                    throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212042.getCode(), OutstockErrorCodeEnum.API_ERROR_212042.getMsg());
                }
                Long contractId = Long.parseLong(data.get(ContractOutstockEnum.REF_ID.getAttr()).toString());
                ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, corpid);
                Double contractMoney = contractEntityExt.getData().getDouble(ContractEnum.AMOUNT.getAttr());
                PaasFormDataEsListVO contractOutstockListVO = saasOutstockHelp.getOutstockListFromEs(corpid, contractId, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode(), validateDataDTO.getDistributorMark());
                double contractOutstockTotalMoney = OutstockUtil.getContractOutstockTotalMoney(data, dataId, contractOutstockListVO);
                // 合同数据
                JSONObject contractEntityExtData = contractEntityExt.getData();
                // 出库单ID集合
                JSONArray outstockIdList = contractEntityExtData.getJSONArray(ContractEnum.OUTSTOCK_ID.getAttr());
                // 校验：合同关联的出库单数量不得大于三百
                if(CollectionUtils.isNotEmpty(outstockIdList) && outstockIdList.size() > 299){
                    throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212049.getCode(), OutstockErrorCodeEnum.API_ERROR_212049.getMsg());
                }
                // 和合同金额比较 1、出库金额是否大于合同金额。2、出库其他费用是否大于合同其他费用。3、出库优惠金额是否大于合同优惠金额。
                // 只有销售出库单的生成规则为销售出库产生应收时才去校验出库金额是否大于合同金额
                Long modelType = fundSetModel.getModelType(corpid,XbbRefTypeEnum.CRM);
                if (Objects.equals(modelType, ModelTypeEnum.OUTSTOCK.getCode())){
                    if(Objects.nonNull(contractMoney) && Arith.compare(contractOutstockTotalMoney, contractMoney) > 0){
                        throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212043.getCode(), OutstockErrorCodeEnum.API_ERROR_212043.getMsg());
                    }
                    List<Long> outstockIds = new ArrayList<>();
                    if (CollectionsUtil.isNotEmpty(outstockIdList)) {
                        for (int i = 0; i < outstockIdList.size(); i++) {
                            Long outstockId = outstockIdList.getLong(i);
                            if (!Objects.equals(outstockId, dataId)) {
                                outstockIds.add(outstockId);
                            }
                        }
                    }
                    // 优惠金额字段
                    String discountAmountAttr = ContractOutstockEnum.DISCOUNT_AMOUNT.getAttr();
                    // 其他费用字段
                    String otherExpenseAttr = ContractOutstockEnum.OTHER_EXPENSE.getAttr();
                    // 合同已出库优惠金额
                    BigDecimal contractOutstockDiscountAmount = BigDecimal.ZERO;
                    // 合同已出库其他费用
                    BigDecimal contractOutstockOtherExpense = BigDecimal.ZERO;
                    if (CollectionsUtil.isNotEmpty(outstockIds)) {
                        List<OutstockEntityExt> outstockEntityExts = outstockModel.listInId(corpid, outstockIds);
                        List<JSONObject> outstockDataList = outstockEntityExts.stream().map(OutstockEntityExt::getData).collect(Collectors.toList());
                        for (JSONObject outstockData : outstockDataList) {
                            if (outstockData.containsKey(discountAmountAttr) && Objects.nonNull(outstockData.getBigDecimal(discountAmountAttr))) {
                                contractOutstockDiscountAmount = contractOutstockDiscountAmount.add(outstockData.getBigDecimal(discountAmountAttr));
                            }
                            if (outstockData.containsKey(otherExpenseAttr) && Objects.nonNull(outstockData.getBigDecimal(otherExpenseAttr))) {
                                contractOutstockOtherExpense = contractOutstockOtherExpense.add(outstockData.getBigDecimal(otherExpenseAttr));
                            }
                        }
                    }
                    // 合同数据必须存在已以出库优惠金额并且销售出库单存在优惠金额
                    if(data.containsKey(discountAmountAttr) && Objects.nonNull(data.getBigDecimal(discountAmountAttr))){
                        // 以出库优惠金额 = 合同已出库优惠金额 + 销售出库单存在优惠金额
                        BigDecimal outstockDiscountAmount = contractOutstockDiscountAmount.add(data.getBigDecimal(discountAmountAttr));
                        // 当以出库优惠金额大于合同优惠金额则抛出异常
                        if (outstockDiscountAmount.compareTo(contractEntityExtData.getBigDecimal(ContractEnum.DISCOUNT_AMOUNT.getAttr())) > 0){
                            throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212048.getCode(), OutstockErrorCodeEnum.API_ERROR_212048.getMsg());
                        }
                    }
                    // 合同数据必须存在已以出库其他费用并且销售出库单存在其他费用
                    if(data.containsKey(otherExpenseAttr) && Objects.nonNull(data.getBigDecimal(otherExpenseAttr))){
                        // 以出库其他费用 = 合同已出库其他费用 + 销售出库单存在其他费用
                        BigDecimal outstockOtherExpense = contractOutstockOtherExpense.add(data.getBigDecimal(otherExpenseAttr));
                        // 当以出库优惠金额大于合同优惠金额则抛出异常
                        if (outstockOtherExpense.compareTo(contractEntityExtData.getBigDecimal(ContractEnum.OTHER_EXPENSE.getAttr())) > 0){
                            throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212047.getCode(), OutstockErrorCodeEnum.API_ERROR_212047.getMsg());
                        }
                    }
                }

                break;
            case RETURNED_PURCHASE_OUTSTOCK:
                SaveFormatHelp.formatLinkBusiness4Save(data, ReturnedPurchaseOutstockEnum.LINK_SUPPLIER.getAttr(), ReturnedPurchaseOutstockEnum.LINK_SUPPLIER_HIDE.getAttr(), ReturnedPurchaseOutstockEnum.LINK_SUPPLIER.getFieldType());
                break;
            case WORK_ORDER_OUTSTOCK:
                SaveFormatHelp.formatLinkBusiness4Save(data, WorkOrderOutstockEnum.LINK_CUSTOMER.getAttr(), WorkOrderOutstockEnum.LINK_CUSTOMER_HIDE.getAttr(), WorkOrderOutstockEnum.LINK_CUSTOMER.getFieldType());
                SaveFormatHelp.formatLinkBusiness4Save(data, WorkOrderOutstockEnum.LINK_CONTACT.getAttr(), WorkOrderOutstockEnum.LINK_CONTACT_HIDE.getAttr(), WorkOrderOutstockEnum.LINK_CONTACT.getFieldType());
                break;
            default:
                break;
        }

        // ==============业务逻辑校验===================
        // 出库单特殊逻辑校验
        // 注意：这里的校验是基于上面关联业务校验之后做的，data格式已经和前端传入的不同，不能和formatLinkBusiness4Save调换顺序
        checkOutstock(data, outstockEntityExt);
        boolean isNew = analyticalHelp.isNew(dataId, taskId, corpid);
        // 新建时出库单产品校验。编辑时不校验，因为编辑时不能修改产品
        checkOutstockProduct2(data, corpid, dataId, taskId, isNew);

        validateDataDTO.setData(data);
    }

    public void checkOutstockProduct2(JSONObject dataList, String corpid, Long dataId, Long taskId, boolean isNew) throws XbbException {
        // 关联单据id
        Long refId = FastJsonHelper.getLongOrDefaultFromFormData(dataList, OutstockEnum.REF_ID.getAttr(), 0L);
        // 出库类型
        Integer type = dataList.getInteger(OutstockEnum.TYPE.getAttr());
        if (Objects.isNull(refId) && !Objects.equals(type, OutstockTypeEnum.OTHER_OUTSTOCK.getCode())) {
            throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212019);
        }
        // 前端出入的产品数组
        JSONArray productArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList,OutstockEnum.PRODUCT.getAttr(),new JSONArray());
        // 先进行统一的产品数量仓库等校验
        if (productArray == null || productArray.isEmpty()) {
            throw new XbbException(InstockErrorCodeEnum.API_ERROR_210033);
        }

        List<Long> pageProductIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,Double> productNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 是否需要合并
        boolean needMerge = false;
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject productObj = productArray.getJSONObject(i);
            Long refProductId = productObj.getLong(BusinessConstant.REF_PRODUCT_ID);
            if (Objects.isNull(refProductId)) {
                needMerge = true;
                break;
            }
        }
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject productObj = productArray.getJSONObject(i);
            Long productId = productObj.getLong(SelectProductEnum.PRODUCT.getAttr());
            pageProductIds.add(productId);
            Double productNum = productObj.getDouble(SelectProductEnum.NUM.getAttr());
            String key;
            if (needMerge) {
                key = productId.toString();
            } else {
                Long refProductId = productObj.getLong(BusinessConstant.REF_PRODUCT_ID);
                key = productId + "_" + refProductId;
            }
            Double num = productNumMap.getOrDefault(key,0D);
            num += productNum;
            productNumMap.put(key,num);
        }

        if (isNew){
            // 校验产品存在与否
            Map<Long,String> pageProductMap = saasProductHelp.productExit(corpid,pageProductIds);
            OutstockTypeEnum outstockTypeEnum = OutstockTypeEnum.getByCode(type);
            switch (outstockTypeEnum){
                case CONTRACT_OUTSTOCK:
                    // 是否允许超发出库
                    boolean overOutstock = false;
                    if (Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
                        //销售出库，可以超发出库
                        ContractEntityExt contractEntity = contractModel.getByKey(refId, corpid);
                        //合同有多模板只能用这个方法唯一定位相应的配置
                        FormConfigEntity overOutstockConfig = formConfigModel.getEntityByFormId(corpid, contractEntity.getFormId(), FormConfigEnum.CONTRACT_ALLOW_OUTSTOCK_PRODUCT_NUM_LARGER_SOLD.getConfig());
                        if (Objects.nonNull(overOutstockConfig)) {
                            if (Objects.equals(overOutstockConfig.getConfigValue(), "1")) {
                                overOutstock = true;
                            }
                        }
                    }
                    Map<String,Double> unOutstockMap = saasProductHelp.getUnOutstockProduct(corpid,refId,type,needMerge,taskId, dataId);
                    ProductUtil.stockProductNumLegalCheck(overOutstock, unOutstockMap,productNumMap,pageProductMap,I18nMessageUtil.getMessage(ErrorMessageConstant.OUT_OF_STOCK_ERROR));
                    break;
                case RETURNED_PURCHASE_OUTSTOCK:
                case TRANSFER_OUTSTOCK:
                case WORK_ORDER_OUTSTOCK:
                    // TODO 可能会有问题
                    unOutstockMap = saasProductHelp.getUnOutstockProduct(corpid,refId,type,needMerge,taskId, dataId);
                    ProductUtil.stockProductNumLegalCheck(false, unOutstockMap,productNumMap,pageProductMap,I18nMessageUtil.getMessage(ErrorMessageConstant.OUT_OF_STOCK_ERROR));
                    break;
                case INVENTORY_OUTSTOCK:
                    InventoryEntityExt inventoryEntityExt = inventoryModel.getByKey(refId, corpid);
                    JSONObject data = inventoryEntityExt.getData();
                    if (Objects.nonNull(data.get(InventoryEnum.OUTSTOCK_ID.getAttr())) && !Objects.equals(data.getLong(InventoryEnum.OUTSTOCK_ID.getAttr()), 0L)) {
                        throw new XbbException(InstockErrorCodeEnum.API_ERROR_210041, String.format(InstockErrorCodeEnum.API_ERROR_210041.getMsg(), inventoryEntityExt.getSerialNo()));
                    }
                    unOutstockMap = saasProductHelp.getUnOutstockProduct(corpid, refId, type, needMerge, taskId, dataId);
                    ProductUtil.stockProductNumLegalCheck(false, unOutstockMap,productNumMap,pageProductMap,I18nMessageUtil.getMessage(ErrorMessageConstant.OUT_OF_STOCK_ERROR));
                    break;
                case MATERIEL_OUTSTOCK:
                    break;
                case ASSEMBLE_OUTSTOCK:
                    break;
                case OTHER_OUTSTOCK:
                    break;
                default:
                    throw new XbbException(InstockErrorCodeEnum.API_ERROR_210034);
            }

            //库存余量校验

        }

        //库存校验
        // 是否库存不足允许出库
        boolean outStockRule = true;
        FormConfigEntity outStockRuleConfigEntity = formConfigModel.getEntityByBusinessType(corpid, XbbRefTypeEnum.OUTSTOCK.getCode(), FormConfigEnum.OUTSTOCK_INSUFFICIENT_NOT_ALLOW_WAREHOUSING.getConfig());
        if (Objects.nonNull(outStockRuleConfigEntity)) {
            if (!Objects.equals(outStockRuleConfigEntity.getConfigValue(), "1")) {
                outStockRule = false;
            }
        }
        if (outStockRule && isNew){
            saasProductHelp.warehouseProductNumLegalCheck(corpid,productArray,null,false, type);
        } else {
            for (int i = 0; i < productArray.size(); i++) {
                JSONObject productObj = productArray.getJSONObject(i);
                SaveFormatHelp.formatLinkBusiness4Save(productObj,SelectProductEnum.WAREHOUSE.getAttr(),"warehouseName",FieldTypeEnum.LINK_BUSINESS_SINGLE.getType());
            }
        }
    }

    /**
     * 校验出库单各字段
     *
     * @param dataList 前端传入的dataList，在上一层校验中已经对关联业务格式做过格式化
     * @param outstockEntityExt 出库单实体，如果为null则为新建，不为null则为编辑
     * @author chaoxiong.lei
     * @Date 20:05 2019/3/1
     * @since v1.0
     * @return void
     **/
    public void checkOutstock(JSONObject dataList, OutstockEntityExt outstockEntityExt) throws XbbException {
        if (dataList == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
        }
        if (outstockEntityExt == null) {
            // 新建出库单不需要进行下面的校验
            return;
        }
        // outbound标志
        JSONObject oriDataList = outstockEntityExt.getData();
//        Integer outbound = oriDataList.getInteger(OutstockEnum.OUTBOUND.getAttr());
        Long dataId = outstockEntityExt.getId();
        // 实际出过库的情况
        if (Objects.nonNull(dataId)) {
            // 出库仓库校验
            Long warehouseId = dataList.getLong(OutstockEnum.WAREHOUSE_ID.getAttr());
            if (!Objects.equals(oriDataList.getLong(OutstockEnum.WAREHOUSE_ID.getAttr()), warehouseId)) {
                throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212005);
            }

            // 实际出过库的情况下，出库类型不允许修改
            Integer type = dataList.getInteger(OutstockEnum.TYPE.getAttr());
            if (!Objects.equals(type, oriDataList.getInteger(OutstockEnum.TYPE.getAttr()))) {
                throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212001);
            }

            // 实际出过库的情况下，关联单据不允许修改
            Long refId = dataList.getLong(OutstockEnum.REF_ID.getAttr());
            if (!Objects.equals(refId, oriDataList.getLong(OutstockEnum.REF_ID.getAttr()))) {
                throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212003);
            }
        }
    }

    /**
     * 出库单保存前，根据subBusinessType设置关联单据类型
     * @param data
     * @param businessType
     */
    private void setRefType(JSONObject data, Integer businessType) {
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        switch (xbbRefTypeEnum){
            case CONTRACT_OUTSTOCK:
                data.put(OutstockEnum.TYPE.getAttr(),String.valueOf(OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()));
                break;
            case RETURNED_PURCHASE_OUTSTOCK:
                data.put(OutstockEnum.TYPE.getAttr(),String.valueOf(OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode()));
                break;
            case OTHER_OUTSTOCK:
                //其他出库前端会传
                break;
            case PRODUCTION_MATERIEL_OUTSTOCK:
                data.put(OutstockEnum.TYPE.getAttr(),String.valueOf(OutstockTypeEnum.MATERIEL_OUTSTOCK.getCode()));
                break;
            case WORK_ORDER_OUTSTOCK:
                data.put(OutstockEnum.TYPE.getAttr(),String.valueOf(OutstockTypeEnum.WORK_ORDER_OUTSTOCK.getCode()));
                break;
            default:
                break;
        }
    }

}
